package im.ok.back.util;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import im.ok.back.common.ServerResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

@Slf4j
public class CommonUtil {

    public static boolean isOsWin() {
        String os = System.getProperty("os.name");
        if (os != null && os.toLowerCase().contains("windows")) {
            return true;
        }
        return false;
    }


    public static Map<String, Object> saveFile(MultipartFile file, String originSuffix, String destSuffix) {
        // 存储在项目中
        ApplicationHome h = new ApplicationHome(CommonUtil.class);
        File source = h.getSource();
        String s = source.getParentFile().toString();
        String originalFilename = file.getOriginalFilename();
        String extension = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase(Locale.ROOT);

        Map<String, Object> map = new HashMap<>();
        if ((StringUtils.isNoneBlank(extension) && extension.equals(originSuffix)) || StringUtils.isBlank(originSuffix)) {
            String originalFilenameWithNoExtension = originalFilename.replace(extension, "");

            String originalFilePath = "";
            String transformFilePath = "";

            String uuid = IdUtil.simpleUUID();
            if (isOsWin()) {
                originalFilePath = s + "\\" + System.currentTimeMillis() + originalFilename;
                transformFilePath = s + "\\" + originalFilenameWithNoExtension + uuid + (StringUtils.isBlank(originSuffix) ? extension : destSuffix);
            } else {
                originalFilePath = s + "/" + System.currentTimeMillis() + originalFilename;
                transformFilePath = s + "/" + originalFilenameWithNoExtension + uuid + (StringUtils.isBlank(originSuffix) ? extension : destSuffix);
            }
            log.info("originalFilePath: {}, transformFilePath: {}", originalFilePath, transformFilePath);
            // D:\tools\back\target\1659449238847下载安装教程.pdf
            // D:\tools\back\target\下载安装教程3660a7a02d93401d80da027d5bb3f73f.doc
            FileOutputStream fos;
            try {
                fos = new FileOutputStream(originalFilePath);
                fos.write(file.getBytes());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            map.put("originalFilePath", originalFilePath);
            map.put("originalFilenameWithNoExtension", originalFilenameWithNoExtension);
            map.put("transformFilePath", transformFilePath);
            map.put("uuid", uuid);
            map.put("extension", extension);
            map.put("fos", fos);
        } else {
            map.put("msg", "文件类型不符！");
        }
        return map;
    }

    public static void turnOffIO (FileOutputStream fos) {
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void deleteFile(String filePath) {
        File orgin = new File(filePath);
        if (orgin.exists() && orgin.isFile()) {
            orgin.delete();
        }
    }

    public static void exportFile(String fileName, String suffix, HttpServletResponse response) {
        ApplicationHome h = new ApplicationHome(CommonUtil.class);
        File source = h.getSource();
        String s = source.getParentFile().toString();
        CommonUtil.doExport(s, fileName, suffix, response);
    }

    public static void doExport(String s, String fileName, String suffix, HttpServletResponse response) {
        // 读取文件流并将去添加到response的输出流中，同时设置响应的Header属性
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            String path = "";
            if (isOsWin()) {
                path = s + "\\" + fileName + suffix;
            } else {
                path = s + "/" + fileName + suffix;
            }

            File file = new File(path);
            inputStream = new FileInputStream(file);
            outputStream = response.getOutputStream();

            // 设置Header
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("utf-8");
            String name = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + name + suffix);
            response.setHeader("Access-Control-Expose-Headers", "Content-disposition");

            try {
                // 将读取的文件流复制到response输出流中
                IOUtils.copy(inputStream, outputStream);
            } catch (IOException e) {
                // 异常情况时，删除文件
                if (file.exists() && file.isFile()) {
                    file.delete();
                }
            }

            outputStream.flush();

            // 关闭流
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            if (file.exists() && file.isFile()) {
                file.delete();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static Map<String, Object> commonProcess (Map<String, Object> resMap, int num) {
        FileOutputStream fos = (FileOutputStream)resMap.get("fos");
        CommonUtil.turnOffIO(fos);

        //转换完之后，删除源文件
        CommonUtil.deleteFile(resMap.get("originalFilePath").toString());
        log.info("源文件删除成功！");

        Map<String, Object> map = new HashMap<>();
        map.put("fileName", resMap.get("originalFilenameWithNoExtension").toString() + resMap.get("uuid").toString());
        map.put("suffix", num);
        return map;
    }

    public static ServerResponse commonProcess4ImageConvert (Map<String, Object> resMap, int num) {
        if (resMap != null && resMap.get("msg") == null) {
            try {
                ImgUtil.convert(FileUtil.file(resMap.get("originalFilePath").toString()), FileUtil.file(resMap.get("transformFilePath").toString()));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return ServerResponse.createSuccessData("上传并转换成功！", CommonUtil.commonProcess(resMap, num));
        }else {
            return ServerResponse.createError(resMap.get("msg").toString());
        }
    }

    public static void generateQRCodeImage (String text, int width, int height, String filePath) throws IOException, WriterException {
        // 转换编码类型，避免中文乱码
        text = new String(text.getBytes("UTF-8"), "iso-8859-1");
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix encode = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
        Path path = FileSystems.getDefault().getPath(filePath);
        MatrixToImageWriter.writeToPath(encode, "PNG", path);
    }

}
